home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Demos / Component Software / FileFlex 2.0.3.sit / FileFlex 2.0.3 / FileFlex Docs / Inside FileFlex (RTF) / FileFlex WorldFlex Update next >
Text File  |  1996-07-21  |  40KB  |  889 lines

  1. Update v2.0.1: FileFlex International WorldFlex Functions
  2.  
  3.    * Understanding Character-Level Sort Order
  4.    * Custom Character Sort Orders
  5.    * Creating a Single-Byte Custom Sort Order Table
  6.    * Creating Single-Byte Sort Order Utility Scripts
  7.    * Understanding Double-Byte Sort Order Tables
  8.    * Creating Double-Byte Sort Order Tables
  9.    * Tricks with Sort Order
  10.    * Setting the Sort Order with FileFlex
  11.  
  12.    * Character Translation
  13.    * Creating Character Translation Utility Scripts
  14.    * Translating Characters Using FileFlex
  15.  
  16.    * Case Translation
  17.    * Creating Case Translation Utility Scripts
  18.    * Intelligent Case Conversion Using FileFlex
  19.    * Standalone Intelligent Case Conversion Function
  20.  
  21. FileFlex is used within multimedia productions throughout the world. While
  22. standard ASCII is prevalent, it is certainly not ubiquitous. When dealing
  23. with international languages, it's necessary to account for differences in
  24. character sorting order, for differences in case conversion, for differences
  25. in character values, and for double-byte characters.
  26.  
  27. FileFlex new WorldFlex technology now gives you the ability to build
  28. international flexibility into your applications with unprecedented power.
  29. FileFlex' WorldFlex technology gives you true dynamic localization. Unlike
  30. virtually all other so-called "world-aware" implementations, you're not
  31. forced to rely on a particular operating system revision or a
  32. country-nationalized version of an application. FileFlex allows you to
  33. define your own international conversion tables and apply them on-the-fly to
  34. any data management task. This dynamic localization functionality allows you
  35. to switch languages, character sets, sort orders, and conversions at any
  36. time throughout the operation of your multimedia production instantly, with
  37. virtually no impact upon FileFlex' already blazing performance.
  38.  
  39. FileFlex WorldFlex' technology falls into these three broad categories:
  40.  
  41.    * Dynamic character-level sort order: FileFlex allows you to use indexes
  42.      and queries that dynamically switch between sort-order tables. Finally,
  43.      an accented "a" character is treated like a regular "a", rather than
  44.      something from Mars. Sort orders can be specified for either
  45.      single-byte or double-byte languages.
  46.  
  47.    * Character translation: As many FileFlex users have discovered, the
  48.      special diacritical characters have different values between Macintosh
  49.      and Windows, and even between DOS and Windows. FileFlex allows you to
  50.      convert characters so that all the diacritical marks (and any other
  51.      conversions you may need) are all in the right places and your
  52.      characters look just right.
  53.  
  54.    * Case conversion: Normal case conversion routines apply a simple
  55.      heuristic to determine the upper case value of a character. Converting
  56.      an "a" to an "A" is simply the matter of subtracting 32. But what about
  57.      converting a "u" with an umlaut to an upper case value? What about
  58.      converting vowels with accents to their equivalent upper case
  59.      characters? FileFlex provides two standalone functions that allow you
  60.      to use custom case conversion tables so that your case conversions make
  61.      sense in your language. FileFlex internal intrinsic index and query
  62.      functions also take into account custom case conversion tables so your
  63.      data can be case insensitive when desired (as opposed to case insane).
  64.  
  65. Before we proceed with details of these functions, we'd like to thank our
  66. customers throughout the world for working with us to understand the
  67. individual needs of different languages and customs and how those needs
  68. apply to the authoring of multimedia productions worldwide.
  69.  
  70. Understanding Character-Level Sort Order
  71.  
  72. ----------------------------------------------------------------------------
  73. Note: The character-level sorting features in FileFlex require that you have
  74. a measurable amount of programming expertise. These features let you modify
  75. the very core of FileFlex data management and require both care to use and
  76. experience to understand. If you're not a pretty advanced scripter or
  77. programmer, you may want to find an experienced "buddy" to team up with
  78. before attempting to utilize these powerful capabilities.
  79. ----------------------------------------------------------------------------
  80. FileFlex uses index files to sort information. When you create an index
  81. file, you're choosing a field that will determine the sort order of the
  82. database. For example, you might choose to sort on zipcode (a numeric code
  83. in the US that helps the post office tell where to deliver mail--in other
  84. countries this is often called the postal code), meaning that records
  85. containing 08553 in the zipcode field will be earlier in the database than
  86. records with 94404 in the zipcode field. Likewise, if you chose to organize
  87. your data based on last name, then "Clinton" would come before "Kennedy".
  88.  
  89. When you switch indexes, FileFlex doesn't reorder the entire database of
  90. records. Instead it adopts a different sort order based on the data in the
  91. fields. FileFlex creates the order of information in an index file when
  92. DBCreateIndex is called. It maintains and updates that order of information
  93. as part of the process of writing a record.
  94.  
  95. When FileFlex updates an index file, it's comparing the values in two
  96. different records. When it looks at "Clinton" and "Kennedy", it looks at the
  97. first characters (i.e., "C" and "K") and determines that "C" comes before
  98. "K" and therefore "Clinton" comes before "Kennedy".
  99.  
  100. This comparison of "C" vs. "K" is based on the standard ordered table we
  101. call ASCII (American Standard Code for Information Interchange). When
  102. FileFlex compares "C" against "K", it's really getting the ASCII value of
  103. "C" (67 decimal) and comparing it to the ASCII value of "K" (75 decimal).
  104. Since 67 comes before 75, then "C" comes before "K".
  105.  
  106. Note: Character sorting is case sensitive. A lower case "c" is ASCII 99
  107. while an upper case "C" is ASCII "67". If you were to compare "clinton"
  108. (note the lower case "c") against "Kennedy", "Kennedy" would come first
  109. because of the ASCII value of "K" (ASCII 75) is less than that of lower case
  110. "c".
  111.  
  112. So, when FileFlex looks at "CLINTON" and "KENNEDY", it's really looking at
  113. the comparative weights (or priorities) of the individual characters,
  114. according to their representation in ASCII. Here's the two strings and their
  115. corresponding values:
  116.  
  117.          C  L  I  N  T  O  N
  118.          67 76 73 78 84 79 78
  119.          |  |  |  |  |  |  |
  120.          75 69 78 78 69 68 89
  121.          K  E  N  N  E  D  Y
  122.  
  123. Custom Character Sort Orders
  124.  
  125. FileFlex' new WorldFlex technology allows you to customize the
  126. character-level sort order used by the FileFlex indexing routines. There are
  127. two primary reasons you might want to do this:
  128.  
  129.    * To sort in descending rather than ascending order
  130.  
  131.    * To sort according to sorting rules different than ASCII, in particular
  132.      for languages other than English.
  133.  
  134. In fact, a very important part of WorldFlex technology is the ability to
  135. change the sort order of your characters, and thereby sort your database
  136. according to the sorting rules you feel are currently appropriate.
  137.  
  138. Many so-called "internationalized", "localized", or "world-aware" systems do
  139. provide support for character sorting order for multi-country use. But they
  140. are usually available only when you're running the localized version of the
  141. operating system or database application. While many of orur friends outside
  142. the US are grateful for any mechanism that recognizes their native language,
  143. FileFlex doesn't stop there. FileFlex' new WorldFlex technology is vastly
  144. more powerful. FileFlex allows you to change your sorting order on-the-fly,
  145. as you switch index files. Nothing else can do this!
  146.  
  147. Here's an example of where this is so powerful: Imagine you're a
  148. multi-national firm with customers throughout the world. When you do a query
  149. to list your customers in the US, the ASCII sort order is just fine. But
  150. when you do a query to list customers in Japan, you want the customers'
  151. names sorted by the appropriate sorting conventions for the Japanese
  152. language and character sets--not according to the rather provincial
  153. expectations of ASCII. With FileFlex, you can switch from an ASCII index to
  154. an index ordered according to Japanese sort order absolutely instantly.
  155.  
  156. Creating a Single-Byte Custom Sort Order Table
  157.  
  158. Character sort orders are controlled by a custom sort order table. For
  159. applications and languages that use single-byte characters (typically,
  160. "roman" languages), each character can be represented by a single byte.
  161. Since a byte is 8-bits wide, this allows for 256 characters.
  162.  
  163. You create a sort order table in your host development environment's
  164. programming language (our examples will be in Director's Lingo). We do this
  165. by building a table containing three bytes of data for each character in the
  166. sort order:
  167.  
  168.    * Leader Flag Byte: For single-byte languages, this byte is always set to
  169.      255.
  170.    * Priority Multiplier Byte: For single-byte languages, this byte is also
  171.      always set to 255.
  172.    * Priority Value Byte: This value signifies the priority of the character
  173.      in the list (never use 0).
  174.  
  175. At the end of all of the three-byte sets, a single byte containing the value
  176. 0 is used to terminate the table.
  177.  
  178. Before we look in more detail at the Priority Value Byte, let's first look
  179. at how ASCII prioritizes it's characters:
  180.  
  181.     A  B  C  D  E     ...  V  W  X  Y  Z
  182.     65 66 67 68 69    ...  86 87 88 89 90
  183.  
  184. Since "A" is an ASCII 65, it's got a lower value than "D", which is an ASCII
  185. 68. The numbers 65 and 68 correspond to the priority value of the various
  186. letters. Likewise, in FileFlex' custom sort order tables, the lower priority
  187. value number, the earlier in the sort the character will be placed. If we
  188. wanted to sort in reverse order ("Z" before "A"), we could assign different
  189. priority values, giving "Z" a much lower number than "A", as in the
  190. following list:
  191.  
  192.     Z  Y  X  W  V     ...  E  D  C  B  A
  193.     65 66 67 68 69    ...  86 87 88 89 90
  194.  
  195. With the priorities show above, if we looked up a "D", we'd see it's value
  196. was 87. Since an "A" has a priority value of 90, the "D" would come earlier
  197. in the list. If we used this set of priority values, "KENNEDY" would
  198. certainly appear before "CLINTON".
  199.  
  200. It's important to remember that the priority value is entirely up to you. If
  201. you wanted all words with vowels (A, E, I, O, and U) to come at the
  202. beginning of the list, you might create the following table of priority
  203. values:
  204.  
  205.     A  E  I  O  U  B  C  D  F  G  H  J  K  L
  206.     65 66 67 68 69 70 71 72 73 74 75 76 77 78 ...
  207.  
  208. FileFlex determines where in the sort order table to find a priority value
  209. based on the character's actual computer-code value (usually ASCII). So,
  210. since "A" has the ASCII code value of 65, FileFlex will look in the 65th
  211. entry in the sort order table to retrieve the priority value. Let's make
  212. this a bit clearer by constructing a partial sort order table for
  213. traditional ASCII (note, we're showing all three data bytes as described
  214. above and all numbers are in base-10):
  215.  
  216.   Entry Pos   65           66           67           68
  217.   US Char     "A"          "B"          "C"          "D"
  218.   Data Bytes  255 255 065  255 255 066  255 255 067  255 255 068
  219.  
  220.   Entry Pos   69           70           71           72
  221.   US Char     "E"          "F"          "G"          "H"
  222.   Data Bytes  255 255 069  255 255 070  255 255 071  255 255 072
  223.  
  224.   Entry Pos   73           74           75           76
  225.   US Char     "I"          "J"          "K"          "L"
  226.   Data Bytes  255 255 073  255 255 074  255 255 075  255 255 076
  227.  
  228. So, to create a FileFlex sort order table that matches traditional ASCII in
  229. ascending order, you'd want "A" to have a sort order priority of 65, so the
  230. third data type at position 65 would be the value 65.
  231.  
  232. Now let's look at how the table would change if we wanted to sort everything
  233. in reverse order (note that we've reversed the entire ASCII character set):
  234.  
  235.   Entry Pos   65           66           67           68
  236.   US Char     "A"          "B"          "C"          "D"
  237.   Data Bytes  255 255 190  255 255 189  255 255 188  255 255 187
  238.  
  239.   Entry Pos   69           70           71           72
  240.   US Char     "E"          "F"          "G"          "H"
  241.   Data Bytes  255 255 186  255 255 185  255 255 184  255 255 183
  242.  
  243.   Entry Pos   73           74           75           76
  244.   US Char     "I"          "J"          "K"          "L"
  245.   Data Bytes  255 255 182  255 255 181  255 255 180  255 255 179
  246.  
  247. Using the above table, when FileFlex encounters the character "A", which has
  248. the ASCII value of 65, it looks at the 65th entry in the table. It then
  249. retrieves the priority value, which is 190. If FileFlex then looks for "C"
  250. (in the 67th entry in the table), it retrieves the priority value of 188.
  251. Since 188 is less than 190, FileFlex will put "C" before "A".
  252.  
  253. Creating Single-Byte Sort Order Utility Scripts
  254.  
  255. The best way to create the sort order table is to write a simple utility
  256. script. Here's an example script that simply builds the ASCII order in ASCII
  257. order:
  258.  
  259.   on buildSortOrder_ASCII
  260.     global ASCII
  261.     put "" into theTable
  262.     repeat with i = 0 to 255
  263.       put the number of chars of theTable into theChar
  264.       put numToChar(255) after theTable -- no leader char
  265.       put numToChar(255) after theTable -- priority multiplier of 0
  266.       if i = 0 then
  267.         put numToChar(255) after theTable -- use 255 in byte 0
  268.       else
  269.         put numToChar(i) after theTable -- priority value
  270.       end if
  271.     end repeat
  272.     put numToChar(0) after theTable -- terminator byte code
  273.     put theTable into ASCII
  274.   end buildSortOrder_ASCII
  275.  
  276. Note the name of the handler is "BuildSortOrder_ASCII". We've developed a
  277. convention where the routine that builds the sort order is called
  278. "BuildSortOrder_" and the name of the sort order itself is appended to the
  279. end. The sort order table is placed in a global variable of the same name.
  280. So, for a sort order for French Canadian, we recommend naming the handler
  281. "BuildSortOrder_FrenchCanadian" and the global variable containing the sort
  282. order "FrenchCanadian".
  283.  
  284. Note that the routine above places the actual byte value into the string by
  285. using numToChar(x). This places a single byte value corresponding to the
  286. number in the string location. Each set of data bytes in the table gets two
  287. bytes with 255 (for the leader char and priority page 0), and the byte
  288. corresponding to the priority value. Finally, after all the data byte sets
  289. are added to the string, BuildSortOrder_ASCII appends a terminator byte
  290. (value 0).
  291.  
  292. Here's an example routine that reverses the ASCII sort order, placing the
  293. table in the global ASCIIReverse:
  294.  
  295.   on buildSortOrder_ASCIIReverse
  296.     global ASCIIReverse
  297.     put "" into theTable
  298.     put 255 into priority
  299.     repeat with i = 0 to 255
  300.       put the number of chars of theTable into theChar
  301.       put numToChar(255) after theTable -- no leader char
  302.       put numToChar(255) after theTable -- priority multiplier of 0
  303.       if i = 0 then
  304.         put numToChar(255) after theTable -- use 255 in byte 0
  305.       else
  306.         put numToChar(priority) after theTable -- priority value
  307.       end if
  308.       put priority-1 into priority
  309.     end repeat
  310.     put numToChar(0) after theTable -- terminator byte code
  311.     put theTable into ASCIIReverse
  312.   end buildSortOrder_ASCIIReverse
  313.  
  314. ----------------------------------------------------------------------------
  315. WARNING: Make absolutely certain you end each sequence with a numToChar(0)
  316. terminator byte. Failure to do this could cause FileFlex to scan beyond the
  317. end of the sort order table and the results could be unpredictable and your
  318. program could abnormally terminate.
  319. ----------------------------------------------------------------------------
  320.  
  321. Understanding Double-Byte Sort Order Tables
  322.  
  323. If the language you're sorting uses double-byte characters (like certain
  324. Japanese and Chinese character sets), you'll need to create double-byte sort
  325. order tables. Double-byte character sets are different because they use two
  326. bytes for many characters. The computer distinguishes between a standard
  327. single-byte character and a dual-byte character by the existence of a leader
  328. byte. This leader byte tells the computer that the byte that follows the
  329. leader byte is to be treated as a special character, rather than simply part
  330. of the standard ASCII table.
  331.  
  332. FileFlex sort order tables are not limited to 256 bytes. Instead, they can
  333. be anywhere from 256 bytes long to 65,280 bytes long (255 * 256). Each set
  334. of 256 bytes in the sort order table is called a "sort order page" and the
  335. maximum number of sort order pages allowed by FileFlex is 255.
  336.  
  337. If you recall from earlier, each character value is represented in the sort
  338. order table by three bytes, a leader char byte, a priority multiplier byte,
  339. and a priority value byte. Also, if you recall, the leader char byte for
  340. single-byte sort order tables was always 255. That told FileFlex to look in
  341. the very first page of the sort order table (i.e., the very first set of 256
  342. bytes) for the character's priority value.
  343.  
  344. When you're using double-byte character sets, you'll need more than one
  345. 256-byte page to represent the sort order. The value that's placed in the
  346. leader character tells FileFlex in which sort order page to look for the
  347. priority value of the character which follows the leader character. Let's
  348. diagram that out:
  349.  
  350. Suppose that your language character set uses characters with the value of
  351. 128 as a leader character. Now, let's suppose your database has a
  352. double-byte character with the values 128 and 065 respectively for the two
  353. bytes. Here's how the sort order table might be be defined:
  354.  
  355.   Sort order page 0
  356.   ---------------------------
  357.   Position #128:  001 255 255
  358.  
  359.   Sort order page 1
  360.   ---------------------------
  361.   Position #65:   255 255 015
  362.  
  363. When reading the character stream, FileFlex would read the first byte and
  364. determine it's value was 128. It would then go to position 128 in the sort
  365. order table and read the first byte. Since the first byte (the leader byte
  366. flag) is not a 255, it would know that 128 was a leader byte. Since the
  367. leader byte flag is 1, FileFlex would know that the next character retrieved
  368. should be compared against sort order page 1 (located in the second bank of
  369. 256 bytes).
  370.  
  371. FileFlex would now read the second byte of the character. Since it knows
  372. that this character is the second of a double-byte character set, FileFlex
  373. will then determine the character's value (in this case 65) and jump 65
  374. bytes into the second sort order page (or to byte 321...256+65...of the full
  375. sort order table). 321 bytes into the table (position 65 in the second page)
  376. FileFlex would look at the priority value byte and determine that the
  377. priority of the character represented by 128 065 is 15.
  378.  
  379. Creating Double-Byte Sort Order Tables
  380.  
  381. You create a double-byte sort order table very much like you would a
  382. single-byte table. You create sets of three-byte sequences for each
  383. character. For each sort order page, you create 256 of these three byte
  384. sets. At the very end, you place a single byte value of 256 that signifies
  385. the termination of the table.
  386.  
  387. You should probably lay out the sort order tables on paper before you
  388. attempt to write the code to generate a table.
  389.  
  390. First, you should determine those byte values that are leader bytes. For
  391. every unique leader byte value, assign a sort order page, from page 1 to
  392. 254. Obviously, you want to keep the number of absolute sort order pages
  393. down as much as possible to make things run faster and to use less memory.
  394. For each leader byte in the sort order byte triplet, make sure you've set
  395. the following two bytes to 255.
  396.  
  397. Next, fill in all the other remaining values in the first 256 byte page. For
  398. each character, assign a weighted value and place that in the third byte of
  399. the data triplet.
  400.  
  401. Note: you can use the second byte of the data triplet as a priority
  402. multiplier. If you need priorities higher than 255, use the priority
  403. multiplier byte by setting it to anything between 1 (earliest in the
  404. priority order) to 254 (last in the priority search list order).
  405.  
  406. After you've filled in the first sort order page, you can then create the
  407. subsequent pages. In these pages, the first byte of the triplet will always
  408. be 255, the second byte between 1 and 254 depending on your desired priority
  409. multiplier, and the third value byte also between 1 and 254.
  410.  
  411. Finally, append a terminator byte--which needs to be a charToNum(0) value.
  412.  
  413. Once you've layed all this out on paper, you can write a BuildSortOrder_
  414. routine that will create a global variable containing your sort order.
  415.  
  416. Tricks with Sort Order
  417.  
  418. You can do some pretty interesting things with sort orders besides handling
  419. international issues. For example, lets assume you wanted to sort numerical
  420. data which you stored in a character field.
  421.  
  422. Note: You should generally do this because the DBF format stores numbers as
  423. ASCII values internally. But if you use character fields to store numbers,
  424. you get to manipulate values with more control (i.e., sort order).
  425.  
  426. So, again, let's assume you've got a character field containing numeric
  427. data. Sometimes, in a numeric field, you might want to have spaces or
  428. asterisks instead of zeros, like in the following example:
  429.  
  430.       "0002598"
  431.       "   2598"
  432.       "***2598"
  433.  
  434. When creating a custom sort order table for numerical sorts in character
  435. fields, you can give the space character (ASCII 32), the asterisk character
  436. (ASCII 42), and the zero all the same priority value weighting. This would
  437. cause the sorting/seeking routines to treat all three characters the same.
  438.  
  439. This kind of "equalizing" of sorting values also applies to those special
  440. international characters, like letters with umlauts (e.g., the double-dots)
  441. or accent marks over characters. You might want to treat a lower case 'a'
  442. and a lower-case 'a' with an accent mark as the same character in sort
  443. order.
  444.  
  445. You can also do this with upper and lower case values. If you want upper
  446. case and lower case letters to be sorted together, give them the same
  447. priority value.
  448.  
  449. Setting the Sort Order with FileFlex
  450.  
  451. You can tell FileFlex to use a new sort order with the FileFlex command
  452. DBSetSortOrder. Unlike most FileFlex commands, DBSetSortOrder is a wrapper
  453. script that does not call FileFlex directly. Instead, DBSetSortOrder sets
  454. two FileFlex global properties: gDBWorldSort and gDBSortOrder.
  455.  
  456. Note: I almost named the gDBSortOrder variable gDBWorldOrder. Then the
  457. function would have been DBSetWorldOrder. But that seemed far too
  458. Republican, so I restrained myself. Wouldn't it be great if you could write
  459. a new translation table, give a quick call to DBSetWorldOrder, and--poof--a
  460. new world order emerges? It gives new (and terrifying meaning) to the phrase
  461. "FileFlex users rule!" [chuckle] [[shiver]].
  462.  
  463. Here's the Lingo code for DBSetSortOrder:
  464.  
  465.   on DBSetSortOrder order
  466.     global gDBWorldSort
  467.     global gDBSortOrder
  468.     if order = EMPTY then
  469.       put EMPTY into gDBWorldSort
  470.     else
  471.       put "1" into gDBWorldSort
  472.       put order into gDBSortOrder
  473.     end if
  474.     return 0
  475.   end DBSetSortOrder
  476.  
  477. When you call DBSetSortOrder, you want to pass your sort order table. Here's
  478. an example:
  479.  
  480.   put DBSetSortOrder(ASCII) into DBResult
  481.  
  482. To disable custom sort order processing, set the sort order to the empty
  483. string:
  484.  
  485.   put DBSetSortOrder("") into DBResult
  486.  
  487. Inside of FileFlex is a C++ function called worldCompare(). When a
  488. DBCreateIndex or DBSeek command is executed, at some time, the internal
  489. worldCompare routine is called upon to compare two strings. When
  490. worldCompare is called, it asks the host development environment (i.e.,
  491. Director) for the value of the reserved global variable gDBWorldSort. If
  492. worldCompare discovers that gDBWorldSort is not empty, it then asks the host
  493. environment for the contents of the global variable gDBSortOrder and uses
  494. that to control the comparison of two strings.
  495.  
  496. Hint: One of the reasons building a sort order table is so complex and
  497. precise is you're building an actual binary data structure that FileFlex can
  498. use directly. While the table may be a bit painful to design once, this
  499. mechanism allows FileFlex to do custom comparisons and switch sort order
  500. tables at blinding speed.
  501.  
  502. To turn off a sort order table, send the empty string to DBSetSortOrder.
  503. When this happens, the global gDBWorldSort is set to the empty string.
  504. FileFlex then knows to skip the extra processing inherent in comparing
  505. world-aware data strings.
  506.  
  507. Cautions: The sort order impacts the internal compare functions; it does not
  508. reorder the dataset or the index. As a result, you should set your sort
  509. order BEFORE you call DBCreateIndex and you should always use the
  510. appropriate sort order table when doing a DBSeek or DBSelectIndex. Failure
  511. to do this could cause your data to appear out of order. When writing
  512. records, try not to get in the situation where two different sort orders
  513. need to be active when writing one record.
  514.  
  515. Here's a sample script from the Sort Order demo file:
  516.  
  517.   on mouseUp
  518.     global ASCIIReverse   -- the reverse sort order table
  519.     -- initialize FF session
  520.     put DBOpenSession() into dbresult
  521.     if dbResult < 0 then
  522.       alert "FileFlex could not initialize!"
  523.       exit
  524.     end if
  525.     -- open a database file
  526.     put dbUse(field "theDBFile") into dbID
  527.     if dbID < 0 then errorClose "Could not open database file."
  528.     --
  529.     -- create a a custom index on TITLE using ASCIIReverse
  530.     --
  531.     buildSortOrder_ASCIIReverse -- build the sort order
  532.     put DBSetSortOrder(ASCIIReverse) into dbResult
  533.     put "Creating index file..." into field "status"
  534.     updateStage
  535.     put dbCreateIndex("REVASCII","TITLE","0","0") into ndxID
  536.     if ndxID < 0 then errorClose "Could not create index file."
  537.     -- fill the list
  538.     put "Scanning data file..." into field "status"
  539.     updateStage
  540.     put DBSelectIndex(ndxID) into dbResult
  541.     if dbResult < 0 then errorClose "Could not select index file."
  542.     put "" into theList
  543.     put DBTop() into dbResult
  544.     repeat while 1 = 1  -- forever
  545.       if theList <> "" then put return after theList
  546.       put DBGetFieldByName("TITLE") into title
  547.       updateStage
  548.       put title after theList
  549.       if DBSkip(1) = 3 then exit repeat
  550.     end repeat
  551.     put theList into field "movie list"
  552.     updateStage
  553.     put DBSetSortOrder(EMPTY) into dbResult -- turn off
  554.     put DBCloseSession() into dbresult
  555.     if dbResult < 0 then
  556.       alert "FileFlex could not terminate!"
  557.       exit
  558.     end if
  559.     put "Processing complete..." into field "status"
  560.     updateStage
  561.   end
  562.  
  563.   on errorClose s
  564.     alert s
  565.     put DBCloseSession() into dbresult
  566.     if dbResult < 0 then
  567.       alert "FileFlex could not terminate!"
  568.       abort
  569.     end if
  570.     abort
  571.   end errorClose
  572.  
  573. ----------------------------------------------------------------------------
  574. Important: FileFlex uses the xBASE/dBASE III standard format. This format
  575. does not permit 8-bit deep characters in memo fields contained within DBT
  576. files. Attempting to do character translation to characters greater than 128
  577. can cause this format difficulties. If you need to store non-ASCII text in
  578. memo fields, you should either use a custom translation table or store your
  579. data in text files and refer to those files from FileFlex fixed-length
  580. fields.
  581. ----------------------------------------------------------------------------
  582.  
  583. Character Translation
  584.  
  585. If you're using a language that has special characters in it's character
  586. sets (i.e., accent marks, umlauts, and other specialty characters), you may
  587. run into an interesting problem moving documents from Macintosh to Windows
  588. or vice-versa. That's because while ASCII is cleanly defined for the US
  589. English character set of "a-zA-Z", that does not mean that character values
  590. of special characters are uniformly used across platforms.
  591.  
  592. FileFlex user Antonio Lucena of Madrid, Spain describes the conversion issue
  593. as it pertains to DOS vs. Windows files as well:
  594.  
  595. "The problem is that Windows uses different character set than MS-DOS (and
  596. the databases created with dBASE). MS-DOS uses OEM Char set, and Windows
  597. uses ANSI. For example in OEM, a diacritical "e" is numbered 130, but in
  598. ANSI, same "e" is numbered 233. The same problem appears when you open a
  599. document (with diachitical vowels on it) made with the EDIT tool from MS-DOS
  600. and you try to open it with the WRITE tool from Windows and no previous
  601. conversion was made."
  602.  
  603. Note: The above message illustrates the value of the free fileflex-talk
  604. mailing list. Another user had discovered the translation problem and by
  605. asking questions to this user and making that dialog public via
  606. fileflex-talk, Antonio was able to see the message and contribute his
  607. feedback. With feedback from him and others, we were able to identify the
  608. need for the new DBTranslateChars function described below.
  609.  
  610. FileFlex WorldFlex technology provides for character-level translation using
  611. much the same mechanism as used for developing sort order tables. You
  612. develop a translation table that describes the new and old values and pass
  613. it to FileFlex along with a container of characters to be translated.
  614.  
  615. Setting up a character translation table is very straightforward. You need
  616. to build a Lingo string consisting of 256 characters. The position in the
  617. string is the value of the old character and the value at that position
  618. becomes the new character.
  619.  
  620. Note: The first character in the string is considered "position 0" by
  621. FileFlex. Also note that you cannot place a 0 into any character position.
  622. If you do not want translation, place the corresponding character value into
  623. that position or the value 255.
  624.  
  625. Creating Character Translation Utility Scripts
  626.  
  627. The best way to create the character translation table is to write a simple
  628. utility script. Here's an example script that simply contains the ASCII
  629. character set:
  630.  
  631.   on buildTranslateTable_ASCIIX
  632.     global ASCIIX
  633.     put "" into theTable
  634.     repeat with i = 0 to 255
  635.       if i = 0 then
  636.         put numToChar(255) after theTable -- use 255 in byte 0
  637.       else
  638.         put numToChar(i) after theTable -- position in table
  639.       end if
  640.     end repeat
  641.     put theTable into ASCIIX
  642.   end buildTranslateTable_ASCIIX
  643.  
  644. Note the name of the handler is "BuildTranslateTable_ASCIIX". We've
  645. developed a convention where the routine that builds the translation table
  646. is called "BuildTranslateTable_" and the name of the translation itself is
  647. appended to the end. In order to prevent confusion from sort order tables,
  648. we've also placed an X after every translation table ("X" for an often used
  649. abbreviation for translate, which is "Xlate"). The translation table is
  650. placed in a global variable of the same name. So, for a translation table
  651. that converts to Windows diacriticals, we recommend naming the handler
  652. "BuildTranslateTable_WinCharX" and the global variable containing the sort
  653. order "WinCharX".
  654.  
  655. Here's an example routine that converts upper case to lower case (and the
  656. reverse):
  657.  
  658.   on buildTranslateTable_CaseReverseX
  659.     global CaseReverseX, ASCIIX
  660.     buildTranslateTable_ASCIIX
  661.     put ASCIIX into theTable
  662.     -- fill in lower case
  663.     repeat with i = 65 to 90
  664.       put numToChar(i+32) into char i+1 of theTable
  665.       -- using i+1 above because strings begin at 1, not 0
  666.     end repeat
  667.     -- fill in upper case
  668.     repeat with i = 97 to 122
  669.       put numToChar(i-32) into char i+1 of theTable
  670.     end repeat
  671.     put theTable into CaseReverseX
  672.   end buildTranslateTable_CaseReverseX
  673.  
  674. The above routine reverses the case, so an upper case "A" becomes a lower
  675. case "a" and vice versa. To create a routine that always converts to upper
  676. case, make both sets of characters upper case. Likewise, to create a routine
  677. that always converts to lower case, make both sets of characters lower case.
  678. Here's an UpperX routine:
  679.  
  680.   on buildTranslateTable_UpperX
  681.     global UpperX, ASCIIX
  682.     buildTranslateTable_ASCIIX
  683.     put ASCIIX into theTable
  684.     -- fill in upper case
  685.     repeat with i = 97 to 122
  686.       put numToChar(i-32) into char i+1 of theTable
  687.       -- using i+1 above because strings begin at 1, not 0
  688.     end repeat
  689.     put theTable into UpperX
  690.   end buildTranslateTable_UpperX
  691.  
  692. ----------------------------------------------------------------------------
  693. WARNING: Make absolutely certain you fill in all 256 bytes. Failure to do
  694. this could cause FileFlex to scan beyond the end of the translation table
  695. and the results could be unpredictable and your program could abnormally
  696. terminate.
  697. ----------------------------------------------------------------------------
  698.  
  699. Translating Characters Using FileFlex
  700.  
  701. You can use FileFlex to translate character sets within a text container
  702. using the DBTranslateChars function. DBTranslateChars takes two parameters:
  703. the string to be translated and the pre-built translation table described
  704. above. It returns the translated string:
  705.  
  706.   put DBTranslateChars(myString,CaseReverseX) into newString
  707.  
  708. Here's a sample routine that will do the character translation (it
  709. presupposes that FileFlex has been initialized properly with DBOpenSession):
  710.  
  711.   on mouseUp
  712.     global CaseReverseX
  713.  
  714.     buildTranslateTable_CaseReverseX
  715.     put DBTranslateChars(field "text data",CaseReverseX)
  716.        into field "text data"
  717.   end mouseUp
  718.  
  719. Case Translation
  720.  
  721. If you're using a language that has special characters in it's character
  722. sets (i.e., accent marks, umlauts, and other specialty characters), you may
  723. run into an interesting problem converting between upper and lower case.
  724. With standard ASCII, it's easy to do a case conversion: just add or subtract
  725. 32 to the character's value. That's because in ASCII, the upper or lower
  726. case character is always algorithmically deterministic. However, when
  727. dealing with international character sets where lower case characters might
  728. have diacritical marks, it becomes much harder. That's because the
  729. characters have a wide variety of values and because there is little
  730. standardization.
  731.  
  732. FileFlex WorldFlex technology provides for intelligent case translation
  733. using much the same mechanism as used for developing character translation
  734. tables. You develop a translation table that describes the new and old
  735. values and pass it to FileFlex along with a container of characters to be
  736. translated.
  737.  
  738. You'll need to set up two case translation tables; one going to upper case
  739. and one going to lower case. For each table, you must build a Lingo string
  740. consisting of 256 characters. The position in the string is the value of the
  741. old character and the value at that position becomes the new character.
  742.  
  743. Note: The first character in the string is considered "position 0" by
  744. FileFlex. Also note that you cannot place a 0 into any character position.
  745. If you do not want translation, place the corresponding character value into
  746. that position or the value 255.
  747.  
  748. Creating Case Translation Utility Scripts
  749.  
  750. The best way to create the case translation table is to write a simple
  751. utility script. Here's an example script that simply converts ASCII lower
  752. case to ASCII upper case:
  753.  
  754.   on buildCaseTable_AsciiUC
  755.     global AsciiUC
  756.     put "" into theTable
  757.     -- Although it takes a few extra cycles, consider
  758.     -- building a full table first, then modifying it below.
  759.     -- This is much easier to understand and test.
  760.     repeat with i = 0 to 255
  761.       if i = 0 then
  762.         put numToChar(255) after theTable -- use 255 in byte 0
  763.       else
  764.         put numToChar(i) after theTable -- position in table
  765.       end if
  766.     end repeat
  767.     -- fill in upper case
  768.      repeat with i = 97 to 122
  769.       put numToChar(i-32) into char i+1 of theTable
  770.       -- using i+1 above because strings begin at 1, not 0
  771.     end repeat
  772.     put theTable into AsciiUC
  773.   end buildCaseTable_AsciiUC
  774.  
  775. Note the name of the handler is "BuildCaseTable_AsciiUC". We've developed a
  776. convention where the routine that builds the translation table is called
  777. "BuildCaseTable_" and the name of the translation itself is appended to the
  778. end. In order to prevent confusion with other tables, we've also placed an
  779. UC after every translation table (for translation to upper case--use "LC"
  780. for translation to lower case). The upper case table is placed in a global
  781. variable of the same name.
  782.  
  783. Here's the routine that translates back down to lower case:
  784.  
  785.   on buildCaseTable_AsciiLC
  786.     global AsciiLC
  787.     put "" into theTable
  788.     -- Although it takes a few extra cycles, consider
  789.     -- building a full table first, then modifying it below.
  790.     -- This is much easier to understand and test.
  791.     repeat with i = 0 to 255
  792.       if i = 0 then
  793.         put numToChar(255) after theTable -- use 255 in byte 0
  794.       else
  795.         put numToChar(i) after theTable -- position in table
  796.       end if
  797.     end repeat
  798.     -- fill in lower case
  799.     repeat with i = 65 to 90
  800.       put numToChar(i+32) into char i+1 of theTable
  801.       -- using i+1 above because strings begin at 1, not 0
  802.     end repeat
  803.     put theTable into AsciiLC
  804.   end buildCaseTable_AsciiLC
  805.  
  806. ----------------------------------------------------------------------------
  807. WARNING: Make absolutely certain you fill in all 256 bytes. Failure to do
  808. this could cause FileFlex to scan beyond the end of the translation table
  809. and the results could be unpredictable and your program could abnormally
  810. terminate.
  811. ----------------------------------------------------------------------------
  812.  
  813. Intelligent Case Conversion Using FileFlex
  814.  
  815. Case translation is used in a number of important ways within FileFlex, in
  816. particular within the intrinsic functions used in indexes and queries, and
  817. through special utility functions provided to perform simple case
  818. conversion.
  819.  
  820. You can tell FileFlex to use a case translation table with the FileFlex
  821. command DBSetCaseTables. Unlike most FileFlex commands, DBSetCaseTables is a
  822. wrapper script that does not call FileFlex directly. Instead,
  823. DBSetCaseTables sets three FileFlex global properties: gDBWorldCase,
  824. gDBWorldUpper and gDBWorldLower.
  825.  
  826. Here's the Lingo code for DBSetCaseTables:
  827.  
  828.   on DBSetCaseTables upperTable, lowerTable
  829.     global gDBWorldCase
  830.     global gDBWorldUpper, gDBWorldLower
  831.     if (upperTable = EMPTY or lowerTable = EMPTY) then
  832.       put EMPTY into gDBWorldCase
  833.     else
  834.       put "1" into gDBWorldCase
  835.       put upperTable into gDBWorldUpper
  836.       put lowerTable into gDBWorldLower
  837.     end if
  838.     return 0
  839.   end DBSetCaseTables
  840.  
  841. When you call DBSetCaseTables, you want to pass your case tables. Here's an
  842. example:
  843.  
  844.   put DBSetCaseTables(AsciiUC, AsciiLC) into DBResult
  845.  
  846. To disable custom case conversion processing, set the sort order to the
  847. empty string:
  848.  
  849.   put DBSetCaseTables("") into DBResult
  850.  
  851. Inside of FileFlex is a C++ function called worldUpper(). When an intrinsic
  852. UPPER function is executed, the internal worldUpper routine is called upon
  853. to do the case conversion. When worldUpper is called, it asks the host
  854. development environment (i.e., Director) for the value of the reserved
  855. global variable gDBWorldCase. If worldUpper discovers that gDBWorldCase is
  856. not empty, it then asks the host environment for the contents of the global
  857. variables gDBWorldUpper and gDBWorldLower and uses them to control the
  858. conversion of the strings.
  859.  
  860. To turn off custom case conversion, send the empty string to
  861. DBSetCaseTables. When this happens, the global gDBWorldCase is set to the
  862. empty string. FileFlex then knows to skip the extra processing inherent in
  863. case conversion of world-aware data strings.
  864.  
  865. Cautions: Be careful that the first parameter is the upper case table and
  866. the second parameter is the lower case table. Also make sure you pass two
  867. tables. Failure to pass two complete case conversion tables could cause
  868. unpredictable results and might lead to abnormal termination.
  869.  
  870. Standalone Intelligent Case Conversion Functions
  871.  
  872. In addition to doing intelligent case conversions within index and query
  873. functions, FileFlex provides you with the ability to do intelligent case
  874. conversions of standalone strings.
  875.  
  876. The function DBUpper will convert a string intelligently from lower case to
  877. upper case. If case tables have already been set with DBSetCaseTables,
  878. DBUpper will use those tables, otherwise it will use the standard ASCII
  879. upper case conversion. Here's how to call DBUpper:
  880.  
  881.   put DBUpper(string) into newString
  882.  
  883. Likewise DBLower will convert a string intelligently from upper case to
  884. lower case. If case tables have already been set with DBSetCaseTables,
  885. DBLower will use those tables, otherwise it will use the standard ASCII
  886. lower case conversion. Here's how to call DBLower:
  887.  
  888.   put DBUpper(string) into newString
  889.